from mininet.topo import Topo
from mininet.net import Mininet
from mininet.log import setLogLevel, info
from mininet.cli import CLI
from mininet.node import Node
from mininet.node import OVSBridge
import time
__metaclass__ = type

class LinuxRouter(Node):
    "A Node with IP forwarding enabled."

    def config(self, **params):
        super(LinuxRouter, self).config(**params)
        # Enable forwarding on the router
        self.cmd('sysctl net.ipv4.ip_forward=1')
        # self.cmd('socat tcp-l:2620,fork,reuseaddr tcp:11.0.0.254:2620 &')

    def terminate(self):
        self.cmd('sysctl net.ipv4.ip_forward=0')
        self.cmd('pkill lt-zebra')
        self.cmd('pkill lt-ospf')
        super(LinuxRouter, self).terminate()


class Rocketfuel(Topo):
    def build(self, **params):
        # add collector host
        c = self.addHost('c', ip='11.0.0.254/24', defaultRoute='via 11.0.0.254')
        s0 = self.addSwitch('s0', cls=OVSBridge)
        self.addLink(c, s0)
        i = 1
        # add routers
        for line in open('1755.r0.cch'):
            arr = line.split()
            self.addNode(arr[0], cls=LinuxRouter, ip='11.0.0.%s/24' % i)
            self.addLink(arr[0], s0)
            i += 1

        # add links
        i = 0
        j = 0
        for line in open('1755.r0.cch'):
            arr = line.split('->')[1].split('=')
            nei_str = arr[0].replace(' ', '')
            nei_ids = nei_str[1:-1].split('><')
            src = line.split()[0]
            for nei in nei_ids:
                if src == nei:
                    continue
                if (nei, src) not in self.links() and (src, nei) not in self.links():
                    self.addLink(src, nei, params1={'ip': '10.%s.%s.1/24' % (j, i)}, params2={'ip': '10.%s.%s.2/24' % (j, i)})
                    i += 1
                    if i == 254:
                        j += 1
                        i = 0


        print self.links(withKeys=True, withInfo=True)


class Mycli(CLI, object):
    def __init__(self, net):
        super(Mycli, self).__init__(net)

    def do_dump_links(self, line):
        for l in self.mn.links:
            if 's0' not in l.intf1.name and 's0' not in l.intf2.name:
                print l.intf1, l.intf2

    def do_link(self, line):
        print '%6f' % time.time()
        super(Mycli, self).do_link(line)

    def do_init_ospf(self, line):
        for node in self.mn.topo.nodes():
            if node == 'c' or node == 's0':
                continue
            net.get(node).cmd('~/frr/zebra/zebra -i tmp/zebra-%s.pid -f r1/zebra.conf -N %s -M fpm:protobuf -d' % (node, node))
            net.get(node).cmd('~/frr/ospfd/ospfd -i tmp/ospfd-%s.pid -f r1/ospfd.conf -N %s -d' % (node, node))
        print '%6f' % time.time()

    def do_batch_down(self, line):
        print '%6f' % time.time()
        super(Mycli, self).do_link("123 124 down")
        super(Mycli, self).do_link("125 127 down")
        super(Mycli, self).do_link("132 134 down")

    def do_batch_up(self, line):
        print '%6f' % time.time()
        super(Mycli, self).do_link("123 124 up")
        super(Mycli, self).do_link("125 127 up")
        super(Mycli, self).do_link("132 134 up")

    def do_batch_downup(self, line):
        print '%6f' % time.time()
        super(Mycli, self).do_link("123 124 down")
        super(Mycli, self).do_link("125 127 down")
        super(Mycli, self).do_link("132 134 down")
        super(Mycli, self).do_link("123 124 up")
        super(Mycli, self).do_link("125 127 up")
        super(Mycli, self).do_link("132 134 up")

if __name__ == '__main__':
    setLogLevel('info')
    topo = Rocketfuel()
    net = Mininet(topo=topo)
    # r1 = net.addHost('r1')  # defaultRoute='via 10.0.0.1')
    # r2 = net.addHost('r2')  # , defaultRoute='via 10.0.1.1')
    # r3 = net.addHost('r3')  # , defaultRoute='via 10.0.1.1')
    # c = net.addHost('c', ip='11.0.0.254/24', defaultRoute='via 11.0.0.254')
    # ms = net.addSwitch('s0')
    # net.addLink(r1, r2, 1, 1)
    # net.addLink(r2, r3, 2, 1)
    # net.addLink(r1, ms, intfName1='r1-eth0', params1={'ip': '11.0.0.1/24'})
    # net.addLink(r2, ms, intfName1='r2-eth0', params1={'ip': '11.0.0.2/24'})
    # net.addLink(r3, ms, intfName1='r3-eth0', params1={'ip': '11.0.0.3/24'})
    # net.addLink(c, ms)
    net.start()


    i = 0
    j = 0
    mi = 1  # management ip index
    for (src, dst, info) in topo.links(withInfo=True):
        # skip the management network
        if src == 'c':
            continue
        if dst == 's0':
        #     net.get(src).cmd('ifconfig %s-eth0 11.0.0.%s/24' % (src, mi))
        #     mi += 1
            continue

        # net.get(src).cmd('ifconfig %s-eth%s 10.%s.%s.1/24' % (src, info['port1'], j, i))
        # net.get(dst).cmd('ifconfig %s-eth%s 10.%s.%s.2/24' % (dst, info['port2'], j, i))
        i += 1
        if i == 254:
            j += 1
            i = 0

    # for node in topo.nodes():
    #     if node == 'c' or node == 's0':
    #         if node == 'c':
    #             net.get('c').cmd('python fpm.py &')
    #         continue
    #     net.get(node).cmd('~/frr/zebra/zebra -i tmp/zebra-%s.pid -f r1/zebra.conf -M fpm:protobuf -d' % node)
    #     net.get(node).cmd('~/frr/ospfd/ospfd -i tmp/ospfd-%s.pid -f r1/ospfd.conf -d' % node)

    print '%6f' % time.time()
    # net.get('r1').cmd('ifconfig r1-eth1 10.0.0.1/24')
    # net.get('r2').cmd('ifconfig r2-eth1 10.0.0.2/24')
    # net.get('r2').cmd('ifconfig r2-eth2 10.0.1.2/24')
    # net.get('r3').cmd('ifconfig r3-eth1 10.0.1.1/24')

    # net.get('c').cmd('python fpm.py > out &')
    # for i in range(1, 4):
    #     # net.get('r%d' % i).cmd('ifconfig r%d-eth0 11.0.0.%d/24 hw ether 76:00:00:00:00:01' % (i, i))
    #     net.get('r%d' % i).cmd('~/frr/zebra/zebra -i r%d/zebra.pid -f r%d/zebra.conf -M fpm:protobuf -d' % (i, i))
    #     net.get('r%d' % i).cmd('~/frr/ospfd/ospfd -i r%d/ospfd.pid -f r%d/ospfd.conf -d' % (i, i))

    # while True:
    #     cmd = raw_input()
    #     if cmd == 'exit':
    #         break
    #     if cmd == 'down':
    #         print '%6f' % time.time()
    #         net.get('123').cmd('ifconfig 123-eth1 down')
    #         net.get('124').cmd('ifconfig 124-eth1 down')
    #     if cmd == 'up':
    #         print '%6f' % time.time()
    #         net.get('123').cmd('ifconfig 123-eth1 up')
    #         net.get('124').cmd('ifconfig 124-eth1 up')

    Mycli(net)
    net.stop()
